﻿using BST250301;
using BST250301.Pages;
using BST250301TestStand.Models;
using BST250301TestStand.Models.Helpers;
using MathNet.Numerics.Distributions;
using NPOI.SS.Formula.Functions;
using NPOI.SS.Formula.PTG;
using OpenTK.Audio.OpenAL;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using static BST250301TestStand.Models.Utils.PLCConfig;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;

namespace BST250301TestStand.Models.Utils
{
    // A class to define all properties of a CAN signal
    public class TCUConfig
    {
        public bool IsConnected = false;
        //public static event EventHandler<MonitorItem> ValueChanged;
        public static nint devHandle = nint.Zero;    // 设备句柄
        public static nint[] chnHandle = new nint[10];  // 通道句柄
        public static int chn_max = 1;                      // 最大通道数量
        public static volatile bool isRunning = true;       // 线程标志
        public static MonitorItem _monitorItem = new MonitorItem();
        private static string _lastRecived = string.Empty;
        private static byte[] _frame_data_122 = new byte[8];
        private static byte[] _frame_data_022 = new byte[8];
        private static ZLGCAN.ZCAN_Transmit_Data _can_data_022;
        private static ZLGCAN.ZCAN_Transmit_Data _can_data_122;
        private static ShowTCUStatusParm _tcu_status = new ShowTCUStatusParm();
        public static event EventHandler<ShowTCUStatusParm> ShowTCUStatus;
        public static event EventHandler<ShowTCUStatusParm> SendTCUData;

        /// <summary>
        /// TCU参数，详见甲方文档
        /// </summary>
        public class ShowTCUStatusParm : EventArgs
        {
            /// <summary>
            /// 报文原型ID至
            /// </summary>
            public string ID { get; set; }
            public string Chn { get; set; }
            public string TimeStamp { get; set; }
            public string IsRx { get; set; }
            public string IsStand { get; set; }
            public string DataDlc { get; set; }
            public string DataStr { get; set; }
            /// <summary>
            /// 阶跃设置值
            /// </summary>
            public string StepSetValue { get; set; }
            /// <summary>
            /// 在线状态
            /// </summary>
            public bool IsOnline { get; set; }
            /// <summary>
            /// 泵速度
            /// </summary>
            public int PumpSpeed { get; set; }
            /// <summary>
            /// 输入轴速度
            /// </summary>
            public int TransmInSpeed { get; set; }
            /// <summary>
            /// 输出轴速度
            /// </summary>
            public int TransmOutSpeed { get; set; }
            /// <summary>
            /// PTO速度
            /// </summary>
            public int PTOSpeed { get; set; }
            /// <summary>
            /// 变速箱油温
            /// </summary>
            public double TransmOilTemp { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public TOil OilTemp { get; set; }
            /// <summary>
            /// 系统压力
            /// </summary>
            public double SystemPressure { get; set; }
            /// <summary>
            /// x压力
            /// </summary>
            public double LubriPressure { get; set; }
            /// <summary>
            /// x温度
            /// </summary>
            public double LubriOilTemp { get; set; }


            /// <summary>
            /// CF反馈电流
            /// </summary>
            public int CF_FBCurrent { get; set; }
            /// <summary>
            /// CR反馈电流
            /// </summary>
            public int CR_FBCurrent { get; set; }
            /// <summary>
            /// PTO反馈电流
            /// </summary>
            public int PTO_FBCurrent { get; set; }
            /// <summary>
            /// CF控制电流
            /// </summary>
            public int CF_ControlCurrent { get; set; }
            /// <summary>
            /// CR控制电流
            /// </summary>
            public int CR_ControlCurrent { get; set; }
            /// <summary>
            /// PTO控制电流
            /// </summary>
            public int PTO_ControlCurrent { get; set; }
            /// <summary>
            /// CF压力
            /// </summary>
            public double CF_Pressure { get; set; }
            /// <summary>
            /// CR压力
            /// </summary>
            public double CR_Pressure { get; set; }
            /// <summary>
            /// CPTO压力
            /// </summary>
            public double CPTO_Pressure { get; set; }
            // <summary>
            /// Pump Pressure
            /// </summary>
            public double PumpPressure { get; set; }
        }

        // 线程传递参数
        class ThreadParams
        {
            public nint devHandle { get; set; }
            public nint chnHandle { get; set; }   // 通道句柄
            public int chnNum { get; set; }         // 通道号
        }
        /// <summary>
        /// 打开can通道
        /// </summary>
        /// <returns></returns>
        public bool OpenCan()
        {
            InitData();
#if DEBUG
            Task.Run(() =>
            {
                while (true)
                {
                    Thread.Sleep(10);
                    _tcu_status.IsOnline = true;
                    _tcu_status.TransmInSpeed = new Random().Next(100, 1300);
                    _tcu_status.TransmOutSpeed = new Random().Next(2200, 3000);
                    _tcu_status.CF_FBCurrent = new Random().Next(100, 1000);
                    _tcu_status.CR_FBCurrent = new Random().Next(200, 2000);
                    _tcu_status.PTO_FBCurrent = new Random().Next(300, 3000);
                    _tcu_status.CF_Pressure = new Random().Next(10, 20);
                    _tcu_status.CR_Pressure = new Random().Next(4, 18);
                    _tcu_status.CPTO_Pressure = new Random().Next(5, 15);
                    _tcu_status.SystemPressure = new Random().Next(2, 40);
                    _tcu_status.CF_ControlCurrent = new Random().Next(500, 1000);
                    _tcu_status.CR_ControlCurrent = new Random().Next(1000, 2000);
                    _tcu_status.PTO_ControlCurrent = new Random().Next(2000, 3000);
                    ShowTCUStatus?.Invoke(this, _tcu_status);
                }
            });
#endif
            try
            {
                // 打开设备
                devHandle = ZLGCAN.ZCAN_OpenDevice(ZLGCAN.ZCAN_PCIe9110, 0, 0);
                if (devHandle == nint.Zero)
                {
                    Console.WriteLine("打开设备失败");
                    return false;
                }
                else
                    Console.WriteLine("打开设备成功");
                // 初始化并打开通道
                for (int i = 0; i < chn_max; i++)
                {
                    chnHandle[i] = Init_chn_USBCAN(devHandle, i);
                    if (chnHandle[i] == nint.Zero)
                    {
                        return false;
                    }
                    var cl = ZLGCAN.ZCAN_ClearBuffer(chnHandle[i]);

                    // 接收线程
                    ThreadParams parameters = new ThreadParams
                    {
                        chnHandle = chnHandle[i],
                        chnNum = i
                    };
                    Thread workerThread = new Thread(ReceiveThread);    // 每通道独立线程接收
                    workerThread.IsBackground = true;                   // 设置为后台线程，不需要join
                    workerThread.Start(parameters);                     // 启动线程
                }
                _tcu_status.IsOnline = true;
                ShowTCUStatus?.Invoke(this, _tcu_status);


                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            _tcu_status.IsOnline = true;
            ShowTCUStatus?.Invoke(this, _tcu_status);
            return false;
        }
        /// <summary>
        /// 关闭can通道
        /// </summary>
        /// <returns></returns>
        public static bool CloseCan()
        {
            isRunning = false;
            uint ret;

            // 关闭通道
            for (int i = 0; i < chn_max; i++)
            {
                if (chnHandle[i] == 0x00)
                    break;
                ret = ZLGCAN.ZCAN_ResetCAN(chnHandle[i]);
                if (ret != 1)
                {
                    Console.WriteLine("关闭通道失败");
                    Console.ReadKey();
                    return false;
                }
                Console.WriteLine("关闭通道成功");
            }
            // 关闭设备
            ret = ZLGCAN.ZCAN_CloseDevice(devHandle);
            if (devHandle == 0x00)
                return true;
            if (ret != 1)
            {
                Console.WriteLine("关闭设备失败");
                Console.ReadKey();
                return false;
            }
            Console.WriteLine("关闭设备成功");
            return true;
        }
        // 初始化并打开通道
        static nint Init_chn_USBCAN(nint dev, int chn_idx)
        {
            nint temp = nint.Zero;
            uint ret;           // 返回值

            // 波特率
            string path = string.Format("{0}/baud_rate", chn_idx);
            ret = ZLGCAN.ZCAN_SetValue(dev, path, "250000");       // 500k
            if (ret != 1)
            {
                Console.WriteLine("设置仲裁域波特率失败");
                Console.ReadKey();
                return nint.Zero;
            }

            // 初始化通道
            ZLGCAN.ZCAN_CHANNEL_INIT_CONFIG InitConfig = new ZLGCAN.ZCAN_CHANNEL_INIT_CONFIG(); // 结构体
            InitConfig.can_type = 0;                // 0 - CAN (USBCAN 只能选择CAN模式)
            InitConfig.config.can.mode = 0;         // 0 - 正常模式，1 - 只听模式
            InitConfig.config.can.acc_code = 0x0;
            InitConfig.config.can.acc_mask = 0x1FFFFFFF;

            nint P2InitConfig = Marshal.AllocHGlobal(Marshal.SizeOf(InitConfig));
            Marshal.StructureToPtr(InitConfig, P2InitConfig, true);                         // 转成指针
            temp = ZLGCAN.ZCAN_InitCAN(dev, (uint)chn_idx, P2InitConfig);
            Marshal.FreeHGlobal(P2InitConfig);                                              // 释放内存
            if (temp == nint.Zero)
            {
                Console.WriteLine("初始化通道失败");
                Console.ReadKey();
                return nint.Zero;
            }
            Console.WriteLine("初始化通道成功");


            //打开通道
            uint Ret = ZLGCAN.ZCAN_StartCAN(temp);
            if (Ret != 1)
            {
                Console.WriteLine("打开通道失败");
                Console.ReadKey();
                return nint.Zero;
            }
            Console.WriteLine("打开通道成功");
            return temp;
        }


        // 构造CANID
        static uint MakeCanId(uint id, int eff, int rtr, int err)
        {
            uint ueff = (uint)(!!Convert.ToBoolean(eff) ? 1 : 0); // 0 标准帧，1 扩展帧
            uint urtr = (uint)(!!Convert.ToBoolean(rtr) ? 1 : 0); // 0 数据帧，1 远程帧
            uint uerr = (uint)(!!Convert.ToBoolean(err) ? 1 : 0); // 0 CAN帧，1 错误帧（目前只能设置为 0）
            return id | ueff << 31 | urtr << 30 | uerr << 29;
        }


        public static string b_array2string(byte[] ByteIn, byte LEN)
        {
            try
            {

                string str = "";
                for (int i = 0; i < LEN; i++)
                {
                    str = str + ByteIn[i].ToString("X2") + " ";
                }
                return str;

            }
            catch (Exception ex)
            {
                return null;
            }
        }
        public static bool ClearBuffer()
        {
            var cl = ZLGCAN.ZCAN_ClearBuffer(chnHandle[0]);
            return cl > 0;
        }
        static void InitData()
        {
            _can_data_022 = new ZLGCAN.ZCAN_Transmit_Data();
            _can_data_022.frame = new ZLGCAN.can_frame();
            _can_data_022.transmit_type = 0;          // 0-正常发送
            _can_data_022.frame.can_id = MakeCanId(0x18FF0022, 1, 0, 0);      // ID,标准帧扩展帧等
            _can_data_022.frame.can_dlc = 8;          // 数据长度
            _can_data_022.frame.__pad |= 0x20;        // 发送回显
            _can_data_022.frame.data = new byte[8];

            _can_data_122 = new ZLGCAN.ZCAN_Transmit_Data();
            _can_data_122.frame = new ZLGCAN.can_frame();
            _can_data_122.transmit_type = 0;          // 0-正常发送
            _can_data_122.frame.can_id = MakeCanId(0x18FF0122, 1, 0, 0);      // ID,标准帧扩展帧等
            _can_data_122.frame.can_dlc = 8;          // 数据长度
            _can_data_122.frame.__pad |= 0x20;        // 发送回显
            _can_data_122.frame.data = new byte[8];
        }
        /// <summary>
        /// 接收数据线程
        /// </summary>
        /// <param name="obj"></param>
        void ReceiveThread(object obj)
        {
            ThreadParams parameters = (ThreadParams)obj;
            ZLGCAN.ZCAN_Receive_Data recData = new ZLGCAN.ZCAN_Receive_Data();
            ZLGCAN.ZCAN_ReceiveFD_Data recFDData = new ZLGCAN.ZCAN_ReceiveFD_Data();

            nint P2zcanReceiveData = Marshal.AllocHGlobal(Marshal.SizeOf(recData) * 100);
            nint P2zcanReceiveFDData = Marshal.AllocHGlobal(Marshal.SizeOf(recFDData) * 100);
            var mItem = new MonitorModel();
            int online = 0;
            while (isRunning)
            {
                uint RecNum = ZLGCAN.ZCAN_GetReceiveNum(parameters.chnHandle, 0);  // 0-CAN 1-CANFD 2-合并
                if (RecNum > 0)
                {
                    online = 0;
                    uint ReceiveNum = ZLGCAN.ZCAN_Receive(parameters.chnHandle, P2zcanReceiveData, 50, 10);
                    if (ReceiveNum > 0)
                    {
                        for (int i = 0; i < 4; i++)
                        {
                            bool isRX = false;
                            bool isStand = false;
                            recData = (ZLGCAN.ZCAN_Receive_Data)Marshal.PtrToStructure(P2zcanReceiveData + i * Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Receive_Data)), typeof(ZLGCAN.ZCAN_Receive_Data));

                            //var cl = ZLGCAN.ZCAN_ClearBuffer(chnHandle[0]);

                            if ((recData.frame.can_id & 1 << 31) != 0)
                                isStand = false;
                            else
                                isStand = true;

                            // 方向
                            if ((recData.frame.__pad & 0x20) == 0x20)
                            { }
                            else
                            {
                                isRX = true;
                            }
                            // ID和数据
                            //Console.WriteLine("ID:{0:X}  {1}", recData.frame.can_id & 0x1FFFFFFF, b_array2string(recData.frame.data, recData.frame.can_dlc));
                            string id = (recData.frame.can_id & 0x1FFFFFFF).ToString("X");
                            string timestamp = recData.timestamp.ToString();
                            string dataarr = b_array2string(recData.frame.data, recData.frame.can_dlc);
                            string dataStr = dataStr = $"{{\"ID\":\"{id}\",\"stand\":\"{isStand}\",\"dlc\":\"{recData.frame.can_dlc}\",\"isRx\":\"{isRX}\",\"chn\":\"{parameters.chnNum}\",\"timestamp\":\"{recData.timestamp.ToString("F6", CultureInfo.InvariantCulture)}\",\"data\":\"{dataarr}\"}}";

                            if (!isRX)
                                dataStr = $"{{\"ID\":\"{id}\",\"stand\":\"{isStand}\",\"dlc\":\"{recData.frame.can_dlc}\",\"isRx\":\"{isRX}\",\"chn\":\"{parameters.chnNum}\",\"timestamp\":\"{recData.timestamp.ToString("F6", CultureInfo.InvariantCulture)}\",\"data\":\"{dataarr}\"}}";
                            _lastRecived = dataStr;
                            SetMonitorItem(dataStr, mItem);
                        }
                        //for (int i = 0; i < ReceiveNum; i++)
                        //{
                        //    bool isRX = false;
                        //    bool isStand = false;
                        //    recData = (ZLGCAN.ZCAN_Receive_Data)Marshal.PtrToStructure(P2zcanReceiveData + i * Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Receive_Data)), typeof(ZLGCAN.ZCAN_Receive_Data));

                        //    var cl = ZLGCAN.ZCAN_ClearBuffer(chnHandle[0]);

                        //    if ((recData.frame.can_id & 1 << 31) != 0)
                        //        isStand = false;
                        //    else
                        //        isStand = true;

                        //    // 方向
                        //    if ((recData.frame.__pad & 0x20) == 0x20)
                        //    { }
                        //    else
                        //    {
                        //        isRX = true;
                        //    }
                        //    // ID和数据
                        //    //Console.WriteLine("ID:{0:X}  {1}", recData.frame.can_id & 0x1FFFFFFF, b_array2string(recData.frame.data, recData.frame.can_dlc));
                        //    string id = (recData.frame.can_id & 0x1FFFFFFF).ToString("X");
                        //    string timestamp = recData.timestamp.ToString();
                        //    string dataarr = b_array2string(recData.frame.data, recData.frame.can_dlc);
                        //    string dataStr = dataStr = $"{{\"ID\":\"{id}\",\"stand\":\"{isStand}\",\"dlc\":\"{recData.frame.can_dlc}\",\"isRx\":\"{isRX}\",\"chn\":\"{parameters.chnNum}\",\"timestamp\":\"{recData.timestamp.ToString("F6", CultureInfo.InvariantCulture)}\",\"data\":\"{dataarr}\"}}";

                        //    if (!isRX)
                        //        dataStr = $"{{\"ID\":\"{id}\",\"stand\":\"{isStand}\",\"dlc\":\"{recData.frame.can_dlc}\",\"isRx\":\"{isRX}\",\"chn\":\"{parameters.chnNum}\",\"timestamp\":\"{recData.timestamp.ToString("F6", CultureInfo.InvariantCulture)}\",\"data\":\"{dataarr}\"}}";

                        //    SendData(dataStr);
                        //}
                    }
                }
                else
                {
                    online++;
                    if (online > 3000)
                    {
                        online = 0;
                        _tcu_status.IsOnline = false;
                        ShowTCUStatus?.Invoke(this, _tcu_status);
                    }
                }
                Thread.Sleep(1);
            }
            Marshal.FreeHGlobal(P2zcanReceiveData);
            Marshal.FreeHGlobal(P2zcanReceiveFDData);
        }
        private void SetMonitorItem(string json, MonitorModel mItem)
        {
            try
            {
                JsonNode node = JsonNode.Parse(json)!;
                string id = node["ID"]!.ToString().Trim();
                _tcu_status.ID = id;
                _tcu_status.TimeStamp = node["timestamp"]!.ToString().Trim();
                _tcu_status.IsStand = node["stand"]!.ToString().Trim();
                _tcu_status.IsRx = node["isRx"]!.ToString().Trim();
                _tcu_status.Chn = node["chn"]!.ToString().Trim();
                string datastr = node["data"]!.ToString().Trim();
                _tcu_status.DataStr = datastr;
                _tcu_status.DataDlc = node["dlc"]!.ToString().Trim();

                //if (DateTime.TryParse(strarr[0], out DateTime cdt))
                //    {
                //        if (_monitorItem.DT != cdt)
                //            _monitorItem.DT = cdt;
                //    }

                //if (strarr[1] == "0X18AABBCCDD")
                //{

                //    double.TryParse(strarr[2], out double oil);
                //    if (_monitorItem.TemperatureOil != oil)
                //        _monitorItem.TemperatureOil = oil;
                //}
                if (id == MainWindow.configapp.TCU1)
                {
                    SetTCU1Vaule(datastr);
                    ShowTCUStatus?.Invoke(this, _tcu_status);
                }
                else if (id == MainWindow.configapp.TCU2)
                {
                    SetTCU2Vaule(datastr);
                    ShowTCUStatus?.Invoke(this, _tcu_status);
                }
                else if (id == MainWindow.configapp.TCU3)
                {
                    SetTCU3Vaule(datastr);
                    ShowTCUStatus?.Invoke(this, _tcu_status);
                }
                else if (id == MainWindow.configapp.TCU4)
                {
                    SetTCU4Vaule(datastr);
                    ShowTCUStatus?.Invoke(this, _tcu_status);
                }
            }
            catch (Exception ex)
            {

            }
            // mItem.ItemValue = _monitorItem;
            //ValueChanged?.Invoke(null, _monitorItem);
        }
        private void SendData(string json)
        {
            try
            {
                JsonNode node = JsonNode.Parse(json)!;
                string id = node["ID"]!.ToString().Trim();
                _tcu_status.ID = id;
                _tcu_status.TimeStamp = node["timestamp"]!.ToString().Trim();
                _tcu_status.IsStand = node["stand"]!.ToString().Trim();
                _tcu_status.IsRx = node["isRx"]!.ToString().Trim();
                _tcu_status.Chn = node["chn"]!.ToString().Trim();
                string datastr = node["data"]!.ToString().Trim();
                _tcu_status.DataStr = datastr;
                _tcu_status.DataDlc = node["dlc"]!.ToString().Trim();

                if (id == MainWindow.configapp.TCU1)
                {
                    SetTCU1Vaule(datastr);
                    SendTCUData?.Invoke(this, _tcu_status);
                }
                else if (id == MainWindow.configapp.TCU2)
                {
                    SetTCU2Vaule(datastr);
                    SendTCUData?.Invoke(this, _tcu_status);
                }
                else if (id == MainWindow.configapp.TCU3)
                {
                    SetTCU3Vaule(datastr);
                    SendTCUData?.Invoke(this, _tcu_status);
                }
                else if (id == MainWindow.configapp.TCU4)
                {
                    SetTCU4Vaule(datastr);
                    SendTCUData?.Invoke(this, _tcu_status);
                }
            }
            catch (Exception ex)
            {
            }
            // mItem.ItemValue = _monitorItem;
            //ValueChanged?.Invoke(null, _monitorItem);
        }
        static void SetTCU1Vaule(string hex)
        {
            // CAN 数据帧
            byte[] data = DataTranslate.Str2ByteArr(hex);
            _tcu_status.IsOnline = true;
            _tcu_status.PumpSpeed = GetintData(data, 0, 0, 16, 0.25, -8000);
            _tcu_status.TransmInSpeed = GetintData(data, 2, 16, 16, 0.25, -8000);
            _tcu_status.TransmOutSpeed = GetintData(data, 4, 32, 16, 0.25, -8000);
            _tcu_status.PTOSpeed = GetintData(data, 6, 48, 16, 0.25, -8000);
        }
        static void SetTCU2Vaule(string hex)
        {
            // CAN 数据帧
            byte[] data = DataTranslate.Str2ByteArr(hex);
            _tcu_status.IsOnline = true;

            _tcu_status.TransmOilTemp = GetDoubleData(data, 0, 0, 16, 0.03125, -273);

            //if (_tcu_status.TransmOilTemp >= 35.00f && _tcu_status.TransmOilTemp <= 45.00f)
            //    _tcu_status.OilTemp = TOil.t40_5;
            //else if (_tcu_status.TransmOilTemp >= 37.00f && _tcu_status.TransmOilTemp <= 43.00f)
            //    _tcu_status.OilTemp = TOil.t40_3;
            //else if (_tcu_status.TransmOilTemp >= 75.00f && _tcu_status.TransmOilTemp <= 85.00f)
            //    _tcu_status.OilTemp = TOil.t80_5;
            //else if (_tcu_status.TransmOilTemp >= 77.00f && _tcu_status.TransmOilTemp <= 83.00f)
            //    _tcu_status.OilTemp = TOil.t80_3;
            ////else if (_tcu_status.TransmOilTemp > -20.00f &&  _tcu_status.TransmOilTemp <= 35.00f)
            ////    _tcu_status.OilTemp = TOil.常温;
            //else if (_tcu_status.TransmOilTemp > 85.00f || _tcu_status.TransmOilTemp <= -20.00f)
            //    _tcu_status.OilTemp = TOil.异常;
            //else
            //    _tcu_status.OilTemp = TOil.常温;

            _tcu_status.SystemPressure = GetDoubleData(data, 2, 16, 8, 0.125, 0);
            _tcu_status.LubriPressure = GetDoubleData(data, 3, 24, 8, 0.125, 0);
            _tcu_status.LubriOilTemp = GetDoubleData(data, 4, 32, 16, 0.03125, -273);

            _tcu_status.PumpPressure = GetDoubleData(data, 6, 48, 8, 0.125, 0);

        }
        static void SetTCU3Vaule(string hex)
        {
            // CAN 数据帧
            byte[] data = DataTranslate.Str2ByteArr(hex);
            _tcu_status.IsOnline = true;
            _tcu_status.CF_FBCurrent = GetintData(data, 0, 0, 11, 1, 0);
            _tcu_status.CR_FBCurrent = GetintData(data, 1, 11, 11, 1, 0);
            _tcu_status.PTO_FBCurrent = GetintData(data, 2, 22, 11, 1, 0);

            _tcu_status.CF_Pressure = GetDoubleData(data, 5, 40, 8, 0.125, 0);
            _tcu_status.CR_Pressure = GetDoubleData(data, 6, 48, 8, 0.125, 0);
            _tcu_status.CPTO_Pressure = GetDoubleData(data, 7, 56, 8, 0.125, 0);
        }
        static void SetTCU4Vaule(string hex)
        {
            // CAN 数据帧
            byte[] data = DataTranslate.Str2ByteArr(hex);
            _tcu_status.IsOnline = true;
            _tcu_status.CF_ControlCurrent = GetintData(data, 0, 0, 11, 1, 0);
            _tcu_status.CR_ControlCurrent = GetintData(data, 1, 11, 11, 1, 0);
            _tcu_status.PTO_ControlCurrent = GetintData(data, 2, 22, 11, 1, 0);
        }
        static int GetintData(byte[] data, int startByte, int bitLength, double resolution, double offset)
        {
            ushort raw = (ushort)(data[startByte] | (data[startByte + 1] << 8));
            var result = raw * resolution + offset;
            return (int)result;
        }
        /// <summary>
        /// 从 CAN 报文数组中解码（读取）信号的物理值。
        /// 转换公式: Physical Value = Raw Value * Resolution + Offset
        /// </summary>
        /// <param name="data">8 字节的 CAN 报文数组。</param>
        /// <param name="startByte">起始字节 (从 1 开始)。</param>
        /// <param name="startBit">起始位 (从 0 开始，整个报文的绝对位)。</param>
        /// <param name="bitLength">信号长度 (位数)。</param>
        /// <param name="resolution">精度/比例。</param>
        /// <param name="offset">偏移量。</param>
        /// <returns>解码后的物理值。</returns>
        public static int GetintData(byte[] data, int startByte, int startBit, int bitLength, double resolution, double offset)
        {
            if (data == null || data.Length != 8)
            {
                throw new ArgumentException("报文数组长度必须为 8 字节。");
            }

            long rawValue = 0;
            //int absoluteStartBit = (startByte) * 8 + startBit;
            int absoluteStartBit = startBit;

            // 1. 从报文读取总线值 (Raw Value)
            for (int i = 0; i < bitLength; i++)
            {
                int currentAbsoluteBit = absoluteStartBit + i;
                int byteIndex = currentAbsoluteBit / 8;
                int bitInByteIndex = currentAbsoluteBit % 8;

                // 检查当前位是否为 1
                if ((data[byteIndex] & (1 << bitInByteIndex)) != 0)
                {
                    // 如果是 1，则设置 rawValue 的相应位
                    rawValue |= (1L << i);
                }
            }

            // 2. 总线值 -> 物理值
            // 仅处理无符号数。如果需要处理有符号数，需额外处理符号位扩展。
            double physicalValue = rawValue * resolution + offset;
            return (int)physicalValue;
        }
        /// <summary>
        /// 从 CAN 报文数组中解码（读取）信号的物理值。
        /// 转换公式: Physical Value = Raw Value * Resolution + Offset
        /// </summary>
        /// <param name="data">8 字节的 CAN 报文数组。</param>
        /// <param name="startByte">起始字节 (从 1 开始)。</param>
        /// <param name="startBit">起始位 (从 0 开始，整个报文的绝对位)。</param>
        /// <param name="bitLength">信号长度 (位数)。</param>
        /// <param name="resolution">精度/比例。</param>
        /// <param name="offset">偏移量。</param>
        /// <returns>解码后的物理值。</returns>
        public static double GetDoubleData(byte[] data, int startByte, int startBit, int bitLength, double resolution, double offset)
        {
            if (data == null || data.Length != 8)
            {
                throw new ArgumentException("报文数组长度必须为 8 字节。");
            }

            long rawValue = 0;
            //int absoluteStartBit = (startByte) * 8 + startBit;
            int absoluteStartBit = startBit;

            // 1. 从报文读取总线值 (Raw Value)
            for (int i = 0; i < bitLength; i++)
            {
                int currentAbsoluteBit = absoluteStartBit + i;
                int byteIndex = currentAbsoluteBit / 8;
                int bitInByteIndex = currentAbsoluteBit % 8;

                // 检查当前位是否为 1
                if ((data[byteIndex] & (1 << bitInByteIndex)) != 0)
                {
                    // 如果是 1，则设置 rawValue 的相应位
                    rawValue |= (1L << i);
                }
            }

            // 2. 总线值 -> 物理值
            // 仅处理无符号数。如果需要处理有符号数，需额外处理符号位扩展。
            double physicalValue = rawValue * resolution + offset;
            return physicalValue;
        }

        public static bool SetCPTOEnable(bool enable)
        {
            try
            {
                _tcu_status.StepSetValue = enable.ToString();

                byte bitdata = 0x00;
                if (enable)
                    bitdata = 0x01;
                nint p2CanData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Transmit_Data)));
                _can_data_122.frame.data = DataTranslate.WriteBits(_can_data_122.frame.data, 12, 1, (uint)bitdata);
                Marshal.StructureToPtr(_can_data_122, p2CanData, true);
                uint ret = ZLGCAN.ZCAN_Transmit(chnHandle[0], p2CanData, 1);//chnHandle =0
                Marshal.FreeHGlobal(p2CanData);
                return ret > 0;
            }
            catch (Exception)
            {
            }
            finally
            {
            }
            return false;
        }
        public static bool SetCPTOOnOff(bool onoff)
        {
            try
            {
                _tcu_status.StepSetValue = onoff.ToString();

                byte bitdata = 0x00;
                if (onoff)
                    bitdata = 0x01;
                nint p2CanData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Transmit_Data)));
                _can_data_122.frame.data = DataTranslate.WriteBits(_can_data_122.frame.data, 13, 1, (uint)bitdata);
                Marshal.StructureToPtr(_can_data_122, p2CanData, true);
                uint ret = ZLGCAN.ZCAN_Transmit(chnHandle[0], p2CanData, 1);//chnHandle =0
                Marshal.FreeHGlobal(p2CanData);
                return ret > 0;
            }
            catch (Exception)
            {
            }
            finally
            {
            }
            return false;
        }
        public static bool SetCFCREnable(bool enable)
        {
            try
            {
                _tcu_status.StepSetValue = enable.ToString();

                byte bitdata = 0x00;
                if (enable)
                    bitdata = 0x01;
                nint p2CanData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Transmit_Data)));
                _can_data_122.frame.data = DataTranslate.WriteBits(_can_data_122.frame.data, 8, 1, (uint)bitdata);
                Marshal.StructureToPtr(_can_data_122, p2CanData, true);
                uint ret = ZLGCAN.ZCAN_Transmit(chnHandle[0], p2CanData, 1);//chnHandle =0
                Marshal.FreeHGlobal(p2CanData);
                return ret > 0;
            }
            catch (Exception)
            {
            }
            finally
            {
            }
            return false;
        }
        public static bool SetCFCRShp(ClutcCFCR cfr)
        {
            try
            {

                byte shp = (byte)cfr;
                _tcu_status.StepSetValue = cfr.ToString();

                nint p2CanData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Transmit_Data)));
                _can_data_122.frame.data = DataTranslate.WriteBits(_can_data_122.frame.data, 9, 3, (uint)shp);
                Marshal.StructureToPtr(_can_data_122, p2CanData, true);
                uint ret = ZLGCAN.ZCAN_Transmit(chnHandle[0], p2CanData, 1);//chnHandle =0
                Marshal.FreeHGlobal(p2CanData);
                return ret > 0;
            }
            catch (Exception)
            {
            }
            return false;

        }
        public static bool SetTransmitType(byte typ)
        {
            try
            {
                _tcu_status.StepSetValue = typ.ToString();

                nint p2CanData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Transmit_Data)));
                _can_data_122.frame.data = DataTranslate.WriteBits(_can_data_122.frame.data, 56, 8, typ);
                Marshal.StructureToPtr(_can_data_122, p2CanData, true);
                uint ret = ZLGCAN.ZCAN_Transmit(chnHandle[0], p2CanData, 1);//chnHandle =0
                Marshal.FreeHGlobal(p2CanData);
                return ret > 0;
            }
            catch (Exception)
            {
            }
            return false;

        }
        /// <summary>
        /// 0bit: CF  CurrentChannel      1bit: CR CurrentChannel    2bit: PTO CurrentChannel   Other bit :Reserve
        /// </summary>
        /// <param name="typ"></param>
        /// <returns></returns>
        public static bool SetCurrentChan(CurrentChannel selectchn)
        {
            try
            {
                byte chn = (byte)selectchn;
                _tcu_status.StepSetValue = selectchn.ToString();
                nint p2CanData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Transmit_Data)));
                _can_data_122.frame.data = DataTranslate.WriteBits(_can_data_122.frame.data, 0, 8, chn);
                //_can_data_122.frame.data = new byte[] { 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
                Marshal.StructureToPtr(_can_data_122, p2CanData, true);
                uint ret = ZLGCAN.ZCAN_Transmit(chnHandle[0], p2CanData, 1);//chnHandle =0
                Marshal.FreeHGlobal(p2CanData);
                return ret > 0;
            }
            catch (Exception)
            {
            }
            return false;

        }
        public static bool SetCurrentCPTO(int ma)
        {
            try
            {
                _tcu_status.StepSetValue = ma.ToString();

                nint p2CanData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Transmit_Data)));
                _can_data_022.frame.data = DataTranslate.WriteBits(_can_data_022.frame.data, 22, 11, (uint)ma);
                Marshal.StructureToPtr(_can_data_022, p2CanData, true);
                uint ret = ZLGCAN.ZCAN_Transmit(chnHandle[0], p2CanData, 1);//chnHandle =0
                Marshal.FreeHGlobal(p2CanData);
                return ret > 0;
            }
            catch (Exception)
            {
            }
            return false;

        }
        public static bool SetCurrentCF(int ma)
        {
            try
            {
                _tcu_status.StepSetValue = ma.ToString();
                if (ma > 1200)
                {

                }
                nint p2CanData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Transmit_Data)));
                _can_data_022.frame.data = DataTranslate.WriteBits(_can_data_022.frame.data, 0, 11, (uint)ma);
                Marshal.StructureToPtr(_can_data_022, p2CanData, true);
                uint ret = ZLGCAN.ZCAN_Transmit(chnHandle[0], p2CanData, 1);//chnHandle =0
                Marshal.FreeHGlobal(p2CanData);
                return ret > 0;
            }
            catch (Exception)
            {
            }
            finally
            {
            }
            return false;
        }
        public static bool SetCurrentCR(int ma)
        {
            try
            {
                _tcu_status.StepSetValue = ma.ToString();

                nint p2CanData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Transmit_Data)));
                _can_data_022.frame.data = DataTranslate.WriteBits(_can_data_022.frame.data, 11, 11, (uint)ma);
                Marshal.StructureToPtr(_can_data_022, p2CanData, true);
                uint ret = ZLGCAN.ZCAN_Transmit(chnHandle[0], p2CanData, 1);//chnHandle =0
                Marshal.FreeHGlobal(p2CanData);
                return ret > 0;
            }
            catch (Exception)
            {
            }
            return false;

        }
        private static byte[] SetOnOff(byte[] canData, bool enable, int startbyte, int startbit, byte on, byte off)
        {
            if (canData == null || canData.Length < 8)
            {
                throw new ArgumentException($"CAN 报文长度必须是 {8} 字节。");
            }
            try
            {
                byte targetByte = canData[startbyte];
                byte controlValue = enable ? on : off;
                int startbit2byte = startbyte % 8;
                byte setMask = (byte)(1 << startbit2byte);
                byte clearMask = (byte)(setMask ^ 0xFF);
                setMask = (byte)(controlValue << startbit2byte);
                targetByte = (byte)(targetByte | setMask);
                canData[startbyte] = targetByte;
            }
            catch (Exception)
            {
            }
            return canData;
        }

    }
}